package com.org.devg.monitor.client;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.org.devg.monitor.client.aspect.MonitorWebAspect;
import com.org.devg.monitor.client.model.MonitorClientConfig;
import com.org.devg.monitor.client.model.MonitorClientRabbit;
import com.org.devg.monitor.client.utils.MonitorUtil;
import com.org.devg.monitor.common.Common;
import com.org.devg.monitor.common.DevgRabbit;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MonitorClientInit implements InitializingBean {

    private final Logger log = LoggerFactory.getLogger(MonitorClientInit.class);

    public static final Map<String, Channel> connectionChannelMap = new ConcurrentHashMap<>();

    private MonitorClientConfig monitorClientConfig;

    public MonitorClientInit(MonitorClientConfig monitorClientConfig) {
        this.monitorClientConfig = monitorClientConfig;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        try {
            if (null == monitorClientConfig || MonitorUtil.isNullOrEmpty(monitorClientConfig.getServerConfigUrl())) {
                log.error("monitorClientConfig cannot be empty...");
                return;
            }
            String specUrl = monitorClientConfig.getServerConfigUrl() + Common.serverConfigUrl;
            String result = getServerConfig(specUrl);
            JSONObject jsonObject = JSONObject.parseObject(result);
            JSONObject dataObject = jsonObject.getJSONObject("data");
            JSONObject rabbitmqObject = dataObject.getJSONObject(Common.rabbitmqConfig);
            Long nodeNumber = dataObject.getLong(Common.nodeNumber);
            if (null != nodeNumber) {
                MonitorWebAspect.nodeNumber = nodeNumber;
            }
            Boolean showStackTraceMsg = dataObject.getBoolean(Common.showStackTraceMsg);
            if (null != showStackTraceMsg) {
                MonitorWebAspect.showStackTraceMsg = showStackTraceMsg;
            }
            MonitorClientRabbit monitorClientRabbit = JSON.toJavaObject(rabbitmqObject, MonitorClientRabbit.class);
//          初始化信道
            initRabbitMqChannel(monitorClientRabbit);
            long intervalTime = 3 * 60 * 60 * 1000; // 3个小时执行一次
            Timer timer = new Timer();
            timer.scheduleAtFixedRate(new ResetMessageNumber(log), intervalTime, intervalTime);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
        }

    }

    public static class ResetMessageNumber extends TimerTask {

        private Logger log;

        public ResetMessageNumber(Logger log) {
            this.log = log;
        }

        @Override
        public void run() {
            try {
                String nowHour = MonitorUtil.localDateTimeFormat(LocalDateTime.now(), "HH");
                Integer hh = Integer.valueOf(nowHour);
                if (null != hh && (hh >= 23 || hh <= 1)) {
                    return;
                }
                String nowDay = MonitorUtil.localDateFormat(LocalDate.now(), "dd");
                log.info("execute ResetMessageNumber start, nowDay:{}", nowDay);
                Integer dd = Integer.valueOf(nowDay);
                int i = dd % 2;
                if (i == 0) {
                    MonitorWebAspect.s1MessageNumber.set(0);
                    log.info("execute ResetMessageNumber end,s1MessageNumber:{}", MonitorWebAspect.s1MessageNumber.get());
                } else {
                    MonitorWebAspect.s0MessageNumber.set(0);
                    log.info("execute ResetMessageNumber end,s0MessageNumber:{}", MonitorWebAspect.s0MessageNumber.get());
                }
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
        }
    }

    public String getServerConfig(String specUrl) throws Exception {
        HttpURLConnection connection = null;
        String result = "";
        try {
            // 1. 得到访问地址的URL
            URL url = new URL(specUrl);
            // 2. 得到网络访问对象java.net.HttpURLConnection
            connection = (HttpURLConnection) url.openConnection();
            /* 3. 设置请求参数（过期时间，输入、输出流、访问方式），以流的形式进行连接 */
            // 设置是否向HttpURLConnection输出
            connection.setDoOutput(false);
            // 设置是否从HttpUrlConnection读入
            connection.setDoInput(true);
            // 设置请求方式
            connection.setRequestMethod("GET");
            // 设置是否使用缓存
            connection.setUseCaches(true);
            // 设置此 HttpURLConnection 实例是否应该自动执行 HTTP 重定向
            connection.setInstanceFollowRedirects(true);
            // 设置超时时间
            connection.setConnectTimeout(3000);
            // 连接
            connection.connect();
            // 4. 得到响应状态码的返回值 responseCode
            int code = connection.getResponseCode();
            // 5. 如果返回值正常，数据在网络中是以流的形式得到服务端返回的数据
            if (code == 200) { // 正常响应
                // 从流中读取响应信息
                BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line = null;
                while ((line = reader.readLine()) != null) { // 循环从流中读取
                    result += line + "\n";
                }
                reader.close(); // 关闭流
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != connection) {
                // 6. 断开连接，释放资源
                connection.disconnect();
            }
        }
        return result;
    }


    private void initRabbitMqChannel(MonitorClientRabbit monitorClientRabbit) throws Exception {
        if (null == monitorClientRabbit) {
            log.error("devg-monitor init devg-monitor-rabbitmq error....");
            return;
        }
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost(monitorClientRabbit.getRabbitHost());
        connectionFactory.setPort(monitorClientRabbit.getRabbitPort());
        connectionFactory.setUsername(monitorClientRabbit.getRabbitUsername());
        connectionFactory.setPassword(monitorClientRabbit.getRabbitPassword());
        String rabbitVirtualHost = monitorClientRabbit.getRabbitVirtualHost();
        if (null != rabbitVirtualHost && !rabbitVirtualHost.equals("")) {
            connectionFactory.setVirtualHost(rabbitVirtualHost);
        }
        Integer multiple = 5;
        connectionFactory.setAutomaticRecoveryEnabled(true);
        connectionFactory.setNetworkRecoveryInterval(2000 * multiple);
        connectionFactory.setRequestedHeartbeat(multiple);
        connectionFactory.setConnectionTimeout(6000 * multiple);
        connectionFactory.setHandshakeTimeout(6000 * multiple);
        Integer poolSize = monitorClientRabbit.getRabbitThreadPoolSize() == null ? 30 : monitorClientRabbit.getRabbitThreadPoolSize();
        ExecutorService es = Executors.newFixedThreadPool(poolSize);
        Connection connection = connectionFactory.newConnection(es);
        if (connection == null) {
            log.error("devg-monitor init rabbit-connection error....");
            return;
        }
        Channel channel = connection.createChannel();
        MonitorClientInit.connectionChannelMap.put(Common.messageRouteKey, channel);
    }
}
